package org.vaadin.teemu.clara; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import java.io.InputStream; import java.util.List; import org.junit.Test; import org.vaadin.teemu.clara.binder.annotation.UiDataSource; import org.vaadin.teemu.clara.binder.annotation.UiField; import org.vaadin.teemu.clara.binder.annotation.UiHandler; import org.vaadin.teemu.clara.inflater.LayoutInflater; import org.vaadin.teemu.clara.inflater.filter.AttributeContext; import org.vaadin.teemu.clara.inflater.filter.AttributeFilter; import org.vaadin.teemu.clara.inflater.filter.AttributeFilterException; import org.vaadin.teemu.clara.inflater.parser.AttributeParser; import com.vaadin.data.Property; import com.vaadin.data.util.ObjectProperty; import com.vaadin.ui.Button; import com.vaadin.ui.Component; import com.vaadin.ui.HorizontalLayout; import com.vaadin.ui.Label; import com.vaadin.ui.Panel; import com.vaadin.ui.VerticalLayout; /** * Tests for {@link ClaraBuilder}. * * @author <a href="mailto:mrotteveel@bol.com">Mark Rotteveel</a> */ public class ClaraBuilderTest { private final ClaraBuilder builder = Clara.build(); @Test public void withController_setsController() { assertNull("Controller should be null before withController call", builder.getController()); final Object controllerInstance = new Object(); ClaraBuilder returnedBuilder = builder .withController(controllerInstance); assertSame("Expected controller set after withController", controllerInstance, builder.getController()); assertSameBuilder(returnedBuilder); } @Test public void withAttributeFilter_addsFilter() { assertTrue("AttributeFilters should initially be empty", builder .getAttributeFilters().isEmpty()); final AttributeFilter filter = new DummyAttributeFilter(); ClaraBuilder returnedBuilder = builder.withAttributeFilter(filter); assertSameObjectsInList("filter", builder.getAttributeFilters(), filter); assertSameBuilder(returnedBuilder); } @Test public void withAttributeFilters_addsFilters_inOrder() { assertTrue("AttributeFilters should initially be empty", builder .getAttributeFilters().isEmpty()); final AttributeFilter filter1 = new DummyAttributeFilter(); final AttributeFilter filter2 = new DummyAttributeFilter(); ClaraBuilder returnedBuilder = builder.withAttributeFilters(filter1, filter2); assertSameObjectsInList("filter", builder.getAttributeFilters(), filter1, filter2); assertSameBuilder(returnedBuilder); } @Test public void combination_withAttributeFilter_withAttributeFilters_inOrder() { assertTrue("AttributeFilters should initially be empty", builder .getAttributeFilters().isEmpty()); final AttributeFilter filter1 = new DummyAttributeFilter(); final AttributeFilter filter2 = new DummyAttributeFilter(); final AttributeFilter filter3 = new DummyAttributeFilter(); final AttributeFilter filter4 = new DummyAttributeFilter(); ClaraBuilder returnedBuilder = builder.withAttributeFilter(filter1) .withAttributeFilters(filter2, filter3) .withAttributeFilter(filter4); assertSameObjectsInList("filter", builder.getAttributeFilters(), filter1, filter2, filter3, filter4); assertSameBuilder(returnedBuilder); } @Test public void withAttributeParser_addsParser() { assertTrue("AttributeFilters should initially be empty", builder .getAttributeParsers().isEmpty()); final AttributeParser parser = new DummyAttributeParser(); ClaraBuilder returnedBuilder = builder.withAttributeParser(parser); assertSameObjectsInList("parser", builder.getAttributeParsers(), parser); assertSameBuilder(returnedBuilder); } @Test public void withAttributeParsers_addsParsers_inOrder() { assertTrue("AttributeFilters should initially be empty", builder .getAttributeParsers().isEmpty()); final AttributeParser parser1 = new DummyAttributeParser(); final AttributeParser parser2 = new DummyAttributeParser(); ClaraBuilder returnedBuilder = builder.withAttributeParsers(parser1, parser2); assertSameObjectsInList("parser", builder.getAttributeParsers(), parser1, parser2); assertSameBuilder(returnedBuilder); } @Test public void combination_withAttributeParser_withAttributeParsers_inOrder() { assertTrue("AttributeFilters should initially be empty", builder .getAttributeParsers().isEmpty()); final AttributeParser parser1 = new DummyAttributeParser(); final AttributeParser parser2 = new DummyAttributeParser(); final AttributeParser parser3 = new DummyAttributeParser(); final AttributeParser parser4 = new DummyAttributeParser(); ClaraBuilder returnedBuilder = builder.withAttributeParser(parser1) .withAttributeParsers(parser2, parser3) .withAttributeParser(parser4); assertSameObjectsInList("parser", builder.getAttributeParsers(), parser1, parser2, parser3, parser4); assertSameBuilder(returnedBuilder); } @Test public void createInflater_fullBuilder() { final Object controller = new Object(); final AttributeFilter filter1 = new DummyAttributeFilter(); final AttributeFilter filter2 = new DummyAttributeFilter(); final AttributeParser parser1 = new DummyAttributeParser(); final AttributeParser parser2 = new DummyAttributeParser(); LayoutInflater inflater = builder.withController(controller) .withAttributeFilters(filter1, filter2) .withAttributeParsers(parser1, parser2).createInflater(); assertNotNull(inflater); // ideally we'd like to test whether the info in the builder // also gets into the inflater; however this currently isn't exposed. } // ClaraBuilder#create(InputStream) is tested through ClaraTest @Test public void withIdPrefix_setsIdPrefix() { assertEquals("idPrefix should initially be empty", "", builder.getIdPrefix()); final String idPrefix = "someIdPrefix"; ClaraBuilder returnedBuilder = builder.withIdPrefix(idPrefix); assertEquals("Unexpected idPrefix", idPrefix, builder.getIdPrefix()); assertSameBuilder(returnedBuilder); } @Test public void withIdPrefix_idPrefixTrimmed() { assertEquals("idPrefix should initially be empty", "", builder.getIdPrefix()); final String idPrefix = " someIdPrefix "; ClaraBuilder returnedBuilder = builder.withIdPrefix(idPrefix); assertEquals("Unexpected idPrefix", idPrefix.trim(), builder.getIdPrefix()); assertSameBuilder(returnedBuilder); } /** * This tests if a controller (annotated without id prefixes) is correctly * wired up if an id prefix is used */ @Test public void testFieldBinding_withIdPrefix() { final SimpleTestController testController = new SimpleTestController(); final String idPrefix = "myIdPrefix_"; VerticalLayout layout = (VerticalLayout) Clara.build() .withController(testController).withIdPrefix(idPrefix) .createFrom(getXml("hierarchy-with-ids.xml")); assertSame("Unexpected layout", layout, testController.verticalLayout); assertEquals("Unexpected layout id", idPrefix + "id1", layout.getId()); // Other ids tested in LayoutInflaterTest assertSame("Unexpected button", layout.getComponent(0), testController.button); assertSame("Unexpected label", ((Panel) layout.getComponent(1)).getContent(), testController.label); assertFalse("Button shouldn't have been pressed yet", testController.buttonPressed); testController.button.click(); assertTrue("Expected click event handler to have been called", testController.buttonPressed); assertSame("Expected label to have property datasource set", testController.property, testController.label.getPropertyDataSource()); } /** * Tests if a preassigned field in a controller (annotated without id * prefix) is correctly inserted in the component tree. */ @Test public void preassignedField_withIdPrefix() { final SimpleTestController testController = new SimpleTestController(); final Button testButton = new Button(); testController.button = testButton; final String idPrefix = "myIdPrefix_"; VerticalLayout layout = (VerticalLayout) Clara.build() .withController(testController).withIdPrefix(idPrefix) .createFrom(getXml("hierarchy-with-ids.xml")); assertSame("Unexpected layout", layout, testController.verticalLayout); assertSame("Button in controller should not have been overwritten", testButton, testController.button); assertSame("Button in layout should be the same as in the controller", testController.button, layout.getComponent(0)); assertEquals("Unexpected id for button (should include prefix)", idPrefix + "id1_1", testButton.getId()); assertFalse("Button shouldn't have been pressed yet", testController.buttonPressed); testController.button.click(); assertTrue("Expected click event handler to have been called", testController.buttonPressed); } @Test public void inflaterListener_componentReuse() { VerticalLayout layout = (VerticalLayout) Clara.build().createFrom( "/org/vaadin/teemu/clara/component-reuse.xml"); assertEquals(2, layout.getComponentCount()); assertCustomComponentInflaterListener("custom1", (CustomComponentInflaterListener) layout.getComponent(0)); assertCustomComponentInflaterListener("custom2", (CustomComponentInflaterListener) layout.getComponent(1)); } @Test public void create_noIdPrefix_prefixOnAllComponentsWithId() { VerticalLayout layout = (VerticalLayout) Clara.build().createFrom( getXml("hierarchy-with-ids.xml")); assertHierarchyWithIds("", layout); } @Test public void create_usingIdPrefix_prefixOnAllComponentsWithId() { final String idPrefix = "myIdPrefix_"; VerticalLayout layout = (VerticalLayout) Clara.build() .withIdPrefix(idPrefix) .createFrom(getXml("hierarchy-with-ids.xml")); assertHierarchyWithIds(idPrefix, layout); } private void assertHierarchyWithIds(String idPrefix, VerticalLayout layout) { assertEquals(idPrefix + "id1", layout.getId()); Button button = (Button) layout.getComponent(0); assertEquals(idPrefix + "id1_1", button.getId()); Panel panel = (Panel) layout.getComponent(1); assertEquals(idPrefix + "id1_2", panel.getId()); Label label = (Label) panel.getContent(); assertEquals(idPrefix + "id1_2_1", label.getId()); HorizontalLayout horizontalLayout = (HorizontalLayout) layout .getComponent(2); assertNull(horizontalLayout.getId()); } private void assertSameBuilder(ClaraBuilder returnedBuilder) { assertSame("Expected same builder", builder, returnedBuilder); } private void assertSameObjectsInList(String objectTypeName, List<?> objectsToCheck, Object... expectedObjects) { assertEquals(String.format("Unexpected number of %ss", objectTypeName), expectedObjects.length, objectsToCheck.size()); for (int idx = 0; idx < expectedObjects.length; idx++) { assertSame(String.format("Unexpected %s object for position %d", objectTypeName, idx), expectedObjects[idx], objectsToCheck.get(idx)); } } private void assertCustomComponentInflaterListener(String expectedRootId, CustomComponentInflaterListener component) { assertEquals("Unexpected id for root", expectedRootId, component.getId()); VerticalLayout layout = (VerticalLayout) component.getCompositionRoot(); assertEquals("Unexpected id for layout", expectedRootId + "_" + "id1", layout.getId()); } private InputStream getXml(String fileName) { return getClass().getClassLoader().getResourceAsStream(fileName); } private static class DummyAttributeFilter implements AttributeFilter { @Override public void filter(AttributeContext attributeContext) throws AttributeFilterException { // Do nothing } } private static class DummyAttributeParser implements AttributeParser { @Override public boolean isSupported(Class<?> valueType) { return false; } @Override public Object getValueAs(String value, Class<?> valueType, Component component) { return null; } } /** * Controller for binding to {@code hierarchy-with-ids.xml}. */ public static class SimpleTestController { private static final String TEST_VALUE = "TestValue"; private boolean buttonPressed; private Property<String> property = new ObjectProperty<String>( TEST_VALUE); @UiField("id1") private VerticalLayout verticalLayout; @UiField("id1_1") private Button button; @UiField("id1_2_1") private Label label; @UiHandler("id1_1") public void onButtonPressed(Button.ClickEvent event) { buttonPressed = true; } @UiDataSource("id1_2_1") public Property<String> propertyForLabel() { return property; } } }